/drawDataSquareBottom { % x v n dataSquareBottom draw box
  len add 2 add exch lbox
} bind def
/drawDataSquareTop { % x v n dataSquareBottom draw box
  neg 1 sub exch lbox
} bind def
/drawDataSquareLeft { % y v n dataSquareBottom draw box
  neg 1 sub 3 1 roll lbox
} bind def
/drawDataSquareRight { % y v n dataSquareBottom draw box
  % use size x y box to draw box
  2 add len add 3 1 roll lbox
} bind def
/drawDataSquareBottomHSB { % x v h s b n dataSquareBottomHSB draw box
  % use size x y box to draw box
  len add 2 add 5 1 roll sethsbcolor lbox
} bind def
/drawDataSquareTopHSB { % x v h s b n dataSquareBottomHSB draw box
  % use size x y box to draw box
  neg 1 sub 5 1 roll sethsbcolor lbox
} bind def
/drawDataSquareLeftHSB { % x v h s b n dataSquareLeftHSB draw box
  % use size x y box to draw box
  neg 1 sub 6 1 roll sethsbcolor lbox
} bind def
/drawDataSquareRightHSB { % x v h s b n dataSquareLeftHSB draw box
  % use size x y box to draw box
  2 add len add 6 1 roll sethsbcolor lbox
} bind def
/drawDataTitleBottom {
  /Helvetica findfont 0.95 scalefont setfont
  0 -1.4 3 -1 roll sub moveto 
  dup stringwidth pop neg 0 rmoveto   
  show
} bind def
/drawDataTitleTop {
  /Helvetica findfont 0.95 scalefont setfont
  0 len 1.6 add 3 -1 roll add moveto 
  dup stringwidth pop neg 0 rmoveto   
  show
} bind def
/drawDataTitleLeft {
  /Helvetica findfont 0.95 scalefont setfont
  neg 1.4 sub len 1 add moveto 
  dup stringwidth pop 0 exch rmoveto -90 rotate
  show 90 rotate
} bind def
/drawDataTitleRight {
  /Helvetica findfont 0.95 scalefont setfont
  1.6 add len add len 1 add moveto 
  dup stringwidth pop 0 exch rmoveto -90 rotate
  show 90 rotate
} bind def
% do not modify the arrays below unless you know what you're doing!
/DataSource     [ /topData /leftData /bottomData /rightData ] def
/DataDrawBox    [ /drawDataSquareTop  /drawDataSquareLeft /drawDataSquareBottom /drawDataSquareRight] def
/DataDrawBoxHSB [ /drawDataSquareTopHSB /drawDataSquareLeftHSB /drawDataSquareBottomHSB /drawDataSquareRightHSB ] def
/DataDrawTitle  [ /drawDataTitleTop /drawDataTitleLeft /drawDataTitleBottom /drawDataTitleRight ] def
% this is the logic to parse the auxiliary linear data
% given in arrays topData, leftData, bottomData, and rightData
% See also the Boolean arrays DataVisible and DataTitles that
% are used to control which part of data will be visible
/drawData {
  0 1 3 {
    % check whether we want to display current data
    dup DataVisible exch get
    {
      % check whether we've actually got some data
      dup DataSource exch get dup currentdict exch known {
        % data source s_j is present, so we load the
        % corresponding data array a and loop over all data sets a[i]
        currentdict exch get dup length 1 sub 0 1 3 -1 roll {
          dup dup
          % now on stack: j a i i i
          % load data set, i.e. a[i]
          4 -1 roll         % j i i i a
          dup 3 -1 roll get dup % j i i a a[i] a[i]
          % 1. check whether we need to process data set title
          6 -1 roll dup 7 1 roll DataTitles exch get {
            % get current title drawing function key
            6 -1 roll dup 7 1 roll DataDrawTitle exch get
            % now on stack: ... j i i a a[i] a[i] title_draw_key
            % get current title and execute drawing function
            exch 0 get exch currentdict exch get 5 -1 roll exch exec
          } { % remove unused variables
              pop 3 -1 roll pop
          } ifelse
          % now on stack: ... j i a a[i]
          % 2. process actual data a[k] for 1 <= k < n
          dup length 1 sub 1 exch getinterval { 
            % on stack: j i a a[i][k]
            gsave
            dup length 2 eq { % print black box if two-valued
              % get box drawing function
              4 -1 roll dup 5 1 roll DataDrawBox exch get currentdict exch get exch
              aload pop 5 -1 roll dup 6 1 roll 4 -1 roll exec
            } {
              dup length 5 eq { % print box with hsb color
                % get box drawing function
                4 -1 roll dup 5 1 roll DataDrawBoxHSB exch get currentdict exch get exch
                % on stack: j i a f a[i]
                % load data array and prepare for drawing
                aload pop 8 -1 roll dup 9 1 roll 7 -1 roll exec
              } { pop } ifelse
            } ifelse
            grestore
          } forall
          exch pop 
          % left on stack: j a
        } for
        
      } if
    } if
  } for
} bind def
